/*
** Copyright (C) 2009 Zhang Cong <ftofficer@ftofficer.com>
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**  
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**  
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**  
*/

#ifndef LIBOI_H_
#define LIBOI_H_

/** OpenInkpot device type. */
typedef enum OI_DEVICE_TYPE
{
    /** Unknown OpenInkpot connect type. */
    OI_DEVICE_UNKNOWN,

    /** OpenInkpot device connected as an SSH server, e.g. Hanlin V3.*/
    OI_DEVICE_SSH_CONNECTED,

    /** OpenInkpot device connected as USB storage, e.g. Hanvon N516. */
    OI_DEVICE_USB_STORAGE,

} OI_DEVICE_TYPE;

typedef struct oi_device_location
{
    OI_DEVICE_TYPE type;
    const char* address;

} oi_device_location;

typedef struct oi_device
{
    oi_device_location dev_loc;

    void* dev_data;

} oi_device;

#include <liboi_err.h>


/**
   @brief Initialize liboi library.

   This function do some library-level initialization. It must
   be called before any other liboi functions.
	
   @return LIBOI_OK if succeeded, or error number otherwise.
 */
liboi_err_t liboi_init();

/**
   @brief Clean up liboi library. It should only be called when
   program stops.
 */
void liboi_cleanup();

#define LOG_DEBUG 100
#define LOG_NORMAL 200
#define LOG_WARN 300
#define LOG_ERROR 400
#define LOG_NOLOG 1000

typedef void (*log_func_t)(const char* file, int line, const char* msg);

void oi_set_log_func(log_func_t log_func);
void oi_set_log_level(int log_level);

/**
   @brief Find all OpenInkpot devices attached.

   @param device_loc [out] Array of all device locations.
   @param device_log_count [in] Count of array item.
                           [out] Count of devices found.

   @return LIBOI_OK if at least one devices is found.
   @return LIBOI_E_NO_DEVICE if no device found.
 */
liboi_err_t oi_find_all(oi_device_location* device_loc,
                        int* device_loc_count);

/**
   @brief Free device location structure.

   @param device_location device pointer.
   @return LIBOI_OK or error code.
 */
liboi_err_t oi_device_location_free(oi_device_location* device_location);

/**
   @brief Connect the device
 */
liboi_err_t oi_device_connect(oi_device_location* device_loc,
                              oi_device** device);

/**
   @brief OpenInkpot device information.
 */
typedef struct oi_device_info
{
    const char* model;          /** Model */
    const char* dev_key;        /** Device Key, may contains '\0' */
    int dev_key_len;            /** Device key length.  */
    const char* oi_version;     /** OpenInkpot version number. */

} oi_device_info;

/**
   @brief Retreive an OpenInkpot device information.
   @param device [in] Connected device
   @param dev_info [out] OpenInkpot device information.
 */
liboi_err_t oi_device_get_info(oi_device* device,
                               oi_device_info* dev_info);

/**
   @brief Execution data. Used by \ref oi_exec_in_device.
 */
struct data_buffer
{
    int length;
    char* data;
};

/**
   @brief Free the execution data.

   After called oi_exec_in_device, you should call this function
   to free the returned stdout_ and stderr_.
 */
void oi_free_data_buffer(struct data_buffer* data);

/**
   @brief Execute command in device.

   @param device [in] The device object returned by \ref oi_device_connect.
   @param command [in] The command to execute in device.
   @param stdin_ [in] The data the command required to read from stdin.
                      May set to NULL if command does not require input.
   @param exit_code [out] The command exit code. This may be NULL if you
                          don't care the exit code.
   @param stdout_ [out] Data the program written to stdout. This may be
                        NULL if you don't care the data.
   @param stderr_ [out] Data the program written to stderr. This may be
                        NULL if you don't care the data.
 */
liboi_err_t oi_exec_in_device(oi_device* device,
                              const char* command,
                              struct data_buffer* stdin_,
                              int* exit_code,
                              struct data_buffer* stdout_,
                              struct data_buffer* stderr_);

/**
   @brief Transfer file from device to host.

   @param device [in] The device.
   @param device_file_path [in] File path in device.
   @param host_file_path [out] File path on host system.

   @return LIBOI_OK(0) for succeess, or other code for failure.
*/
liboi_err_t oi_get_file(oi_device* device,
                        const char* device_file_path,
                        const char* host_file_path);

/**
   @brief Transfer file from host to device.

   @param device [in] The device.
   @param host_file_path [out] File path on host system.
   @param device_file_path [in] File path in device.

   @return LIBOI_OK(0) for succeess, or other code for failure.
*/
liboi_err_t oi_put_file(oi_device* device,
                        const char* host_file_path,
                        const char* device_file_path);

/**
   @brief Disconnect to OpenInkpot device.

   After disconnect, it is not
   allowed to continue using the device object. The only allowed call
   after disconnect is \ref oi_device_free.

   @param device [in] The device.
 */
liboi_err_t oi_device_disconnect(oi_device* device);


/**
   @brief Free device structure in memory.

   @param device [in] The device.
 */
liboi_err_t oi_device_free(oi_device* device);

#endif // LIBOI_H_
